package com.example.friend.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.core.constants.CacheConstants;
import com.example.core.constants.Constants;
import com.example.core.constants.HttpConstants;
import com.example.core.entity.LoginUser;
import com.example.core.enums.ResultCode;
import com.example.core.enums.UserIdentity;
import com.example.core.enums.UserStatus;
import com.example.core.utils.ThreadLocalUtil;
import com.example.friend.component.manager.UserCacheManager;
import com.example.friend.entity.DO.ExamDO;
import com.example.friend.entity.DO.UserDO;
import com.example.friend.entity.DTO.UserUpdateDTO;
import com.example.friend.entity.VO.LoginUserVO;
import com.example.friend.entity.VO.UserDetailVO;
import com.example.friend.mapper.UserMapper;
import com.example.friend.service.IUserService;
import com.example.message.service.AliSmsService;
import com.example.redis.service.RedisService;
import com.example.security.exception.ServiceException;
import com.example.security.service.TokenService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private RedisService redisService;
    @Autowired
    private AliSmsService aliSmsService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private UserCacheManager userCacheManager;

    @Value("${jwt.secret}")
    private String secret;

    @Value("${file.oss.downloadUrl}")
    private String downloadUrl;

    @Value("${sms.aliyun.isSend}")
    private boolean isSend;


    @Override
    public boolean sendCode(String phoneNum) {
        // 校验手机号
        Pattern regex = Pattern.compile("^1[2-9]\\d{9}$");
        Matcher m = regex.matcher(phoneNum);
        if (!m.matches()) {
            throw new ServiceException(ResultCode.FAILED_USER_PHONE);
        }
        // 校验验证码是否过期
        Long expire = redisService.getExpire(phoneNum, TimeUnit.SECONDS);
        if (expire != -2 && expire < CacheConstants.PHONE_CODE_EXPIRE){
            throw new ServiceException(ResultCode.FAILED_FREQUENT);
        }
        // 生成验证码并存储到redis中
        String code = RandomUtil.randomNumbers(6);
        String phoneCodeKey = this.appendPhoneCodeKey(phoneNum);
        redisService.setCacheObject(phoneCodeKey, code, CacheConstants.PHONE_CODE_EXPIRE, CacheConstants.TIME_UNIT);
        // 发送短信
        if (isSend) {
            boolean send = aliSmsService.sendMobileCode(phoneNum, code);
            if (!send) {
                throw new ServiceException(ResultCode.FAILED_SEND_CODE);
            }
        }
        return true;
    }

    @Override
    public String login(String phone, String code) {
        // 比对验证码
        String phoneCodeKey = this.appendPhoneCodeKey(phone);
        String cacheCode = redisService.getCacheObject(phoneCodeKey, String.class);
        if (StrUtil.isEmpty(cacheCode) || !cacheCode.equals(code)) {
            throw new ServiceException(ResultCode.FAILED_ERROR_CODE);
        }
        redisService.deleteObject(phoneCodeKey);
        LambdaQueryWrapper<UserDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDO::getPhone, phone);
        UserDO user = userMapper.selectOne(wrapper);
        if (user == null) {
            // 新用户注册
            user = new UserDO();
            user.setPhone(Constants.getDefaultNickname(phone));
            user.setNickName(phone);
            user.setStatus(UserStatus.NORMAL.getStatus());
            user.setCreateUser(Constants.SYSTEM_USER_ID);
            userMapper.insert(user);
        }
        LoginUser loginUser = new LoginUser(user.getUserId(), UserIdentity.NORMAL.getValue(),
                user.getNickName(), user.getHeadImage());

        return tokenService.createToken(loginUser, secret);
    }

    @Override
    public boolean logout(String token) {
        if (StrUtil.isNotEmpty(token) && token.startsWith(HttpConstants.PREFIX)) {
            token = token.replaceFirst(HttpConstants.PREFIX, StrUtil.EMPTY);
        }
        return tokenService.deleteLoginUser(token, secret);
    }

    @Override
    public LoginUserVO getLoginUserInfo(String token) {
        token = tokenService.parseToken(token);
        LoginUser loginUser = tokenService.getUserInfo(token, secret);
        if (loginUser == null) {
            return null;
        }
        LoginUserVO loginUserVO = new LoginUserVO();
        loginUserVO.setNickName(loginUser.getNickname());
        if (StrUtil.isNotEmpty(loginUser.getHeadImage())) {
            loginUserVO.setHeadImage(downloadUrl + loginUser.getHeadImage());
        }
        return loginUserVO;
    }

    @Override
    public UserDetailVO detail() {
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
        if (userId == null) {
            throw new ServiceException(ResultCode.FAILED_USER_NOT_EXISTS);
        }
        UserDetailVO userVO = userCacheManager.getUserById(userId);
        if (userVO == null) {
            throw new ServiceException(ResultCode.FAILED_USER_NOT_EXISTS);
        }
        if (StrUtil.isNotEmpty(userVO.getHeadImage())) {
            userVO.setHeadImage(downloadUrl + userVO.getHeadImage());
        }
        return userVO;
    }

    @Override
    public int edit(UserUpdateDTO userUpdateDTO) {
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
        if (userId == null) {
            throw new ServiceException(ResultCode.FAILED_USER_NOT_EXISTS);
        }
        UserDO user = userMapper.selectById(userId);
        if (user == null) {
            throw new ServiceException(ResultCode.FAILED_USER_NOT_EXISTS);
        }
        BeanUtils.copyProperties(userUpdateDTO, user);
        //更新用户缓存
        userCacheManager.refreshUser(user);
        tokenService.refreshLoginUser(user.getNickName(),user.getHeadImage(),
                ThreadLocalUtil.get(Constants.TOKEN_KEY, String.class));
        return userMapper.updateById(user);
    }


    @Override
    public int updateHeadImage(String headImage) {
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
        if (userId == null) {
            throw new ServiceException(ResultCode.FAILED_USER_NOT_EXISTS);
        }
        UserDO user = userMapper.selectById(userId);
        if (user == null) {
            throw new ServiceException(ResultCode.FAILED_USER_NOT_EXISTS);
        }
        user.setHeadImage(headImage);
        //更新用户缓存
        userCacheManager.refreshUser(user);
        tokenService.refreshLoginUser(user.getNickName(),user.getHeadImage(),
                ThreadLocalUtil.get(Constants.TOKEN_KEY, String.class));
        return userMapper.updateById(user);
    }


    /**
     * 拼接 key
     * @param phoneNum phoneNum
     * @return key
     */
    private String appendPhoneCodeKey(String phoneNum) {
        return CacheConstants.PHONE_CODE_KEY + phoneNum;
    }

}

